﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web.Caching;
using ChannelVN.Cached.Config;
using Enyim.Caching;
using System.Web;

namespace ChannelVN.Cached.CacheClients
{
    public class Memcached
    {
        /// <summary>
        /// Max expire time (seconds) => 30 days
        /// </summary>
        public const int MaxExpireTime = 60 * 60 * 24 * 30;

        private bool UseCachedKeyManager
        {
            get { return ConfigurationManager.AppSettings["UseCachedKeyManager"] == "1"; }
        }

        private readonly MemcachedClient _memcachedClient;

        private string CacheClientName { get; set; }

        private string EnyimCachedSectionName { get; set; }

        private static CacheSettings CacheSettings
        {
            get
            {
                return CacheSettings.GetCurrentSettings();
            }
        }

        public bool EnableCache { get; set; }

        public Memcached(string cacheClientName, string enyimCachedSectionName)
        {
            CacheClientName = cacheClientName;
            EnyimCachedSectionName = enyimCachedSectionName;

            _memcachedClient = new MemcachedClient("enyim.com/" + enyimCachedSectionName);
        }

        public bool Add(string groupName, string cachedKey, object cachedValue)
        {
            return Add(groupName, cachedKey, cachedValue, DateTime.Now.AddSeconds(CacheSettings.DefaultCacheExpire));
        }
        public bool Add(string groupName, string cachedKey, object cachedValue, long numberOfSecondToExpired)
        {
            return Add(groupName, cachedKey, cachedValue, DateTime.Now.AddSeconds(numberOfSecondToExpired));
        }
        public bool Add(string groupName, string cachedKey, object cachedValue, DateTime expireAt)
        {
            if (!EnableCache) return false;

            var publishedKey = "";
            var isExistsCached = true;

            if (UseCachedKeyManager && !string.IsNullOrEmpty(groupName))
            {
                //var currentCachedKeyGroups = MemcachedKeyGroups.Current;
                //var isExistsCached = currentCachedKeyGroups.ContaintsKey(groupName, cachedKey);
                //publishedKey = currentCachedKeyGroups.UpdateKeyInfo(groupName, cachedKey, DateTime.Now, expireAt);
                //if (isExistsCached) _memcachedClient.Remove(publishedKey);

                var currentSimplCachedKeyGroups = SimpleMemcachedKeyGroup.Current;
                isExistsCached = currentSimplCachedKeyGroups.ContaintsKey(groupName, cachedKey);
                publishedKey = currentSimplCachedKeyGroups.UpdateKeyInfo(groupName, cachedKey);
            }
            else
            {
                publishedKey = cachedKey;
            }
            if (isExistsCached) _memcachedClient.Remove(publishedKey);
            _memcachedClient.Store(Enyim.Caching.Memcached.StoreMode.Set, publishedKey, cachedValue, expireAt);

            return true;
        }

        public object Get(string groupName, string cachedKey)
        {
            if (!EnableCache) return null;

            var publishedKey = "";

            if (UseCachedKeyManager && !string.IsNullOrEmpty(groupName))
            {
                //var currentCachedKeyGroups = MemcachedKeyGroups.Current;
                //if (!currentCachedKeyGroups.ContaintsKey(groupName, cachedKey)) return null;
                //publishedKey = currentCachedKeyGroups[groupName].GetPublishedKey(cachedKey);

                //var currentSimpleCachedKeyGroups = SimpleMemcachedKeyGroup.Current;
                //if (!currentSimpleCachedKeyGroups.ContaintsKey(groupName, cachedKey)) return null;
                //publishedKey = currentSimpleCachedKeyGroups.GetMemcachedKey(groupName, cachedKey);

                publishedKey = SimpleMemcachedKeyGroup.GetPublishKey(groupName, cachedKey);
            }
            else
            {
                publishedKey = cachedKey;
            }
            try
            {
                return !string.IsNullOrEmpty(publishedKey) ? _memcachedClient.Get(publishedKey) : null;
            }
            catch (Exception)
            {
                return null;
            }
        }
        public T Get<T>(string groupName, string cachedKey)
        {
            if (!EnableCache) return default(T);
            var publishedKey = "";
            if (UseCachedKeyManager && !string.IsNullOrEmpty(groupName))
            {
                //var currentCachedKeyGroups = MemcachedKeyGroups.Current;
                //if (!currentCachedKeyGroups.ContaintsKey(groupName, cachedKey)) return default(T);
                //publishedKey = currentCachedKeyGroups[groupName].GetPublishedKey(cachedKey);

                //var currentCachedKeyGroups = MemcachedKeyGroups.Current;
                //if (!currentCachedKeyGroups.ContaintsKey(groupName, cachedKey)) return default(T);
                //publishedKey = currentCachedKeyGroups[groupName].GetPublishedKey(cachedKey);

                publishedKey = SimpleMemcachedKeyGroup.GetPublishKey(groupName, cachedKey);
            }
            else
            {
                publishedKey = cachedKey;
            }
            try
            {
                return !string.IsNullOrEmpty(publishedKey) ? _memcachedClient.Get<T>(publishedKey) : default(T);
            }
            catch (Exception)
            {
                return default(T);
            }
        }
        public IDictionary<string, object> Get(string groupName, params string[] cachedKeys)
        {
            if (!EnableCache) return null;

            IDictionary<string, object> returnValues = new Dictionary<string, object>();

            if (UseCachedKeyManager && !string.IsNullOrEmpty(groupName))
            {
                //var currentCachedKeyGroups = MemcachedKeyGroups.Current;

                // Group có tồn tại
                //if (!currentCachedKeyGroups.ContaintsGroup(groupName)) return null;

                //IList<string> keysList = (from key in cachedKeys
                //                          where currentCachedKeyGroups[groupName].ContainsKey(key)
                //                          select currentCachedKeyGroups[groupName].GetPublishedKey(key)).ToList();

                //if (keysList.Count == 0) return null;

                //var memcachedValues = _memcachedClient.Get(keysList);

                //foreach (var key in memcachedValues.Keys)
                //{
                //    returnValues.Add(key, memcachedValues[currentCachedKeyGroups[groupName].GetPublishedKey(key)]);
                //}

                var keysList = cachedKeys.Select(cachedKey => SimpleMemcachedKeyGroup.GetPublishKey(groupName, cachedKey)).ToList();
                var memcachedValues = _memcachedClient.Get(keysList);
                foreach (var key in memcachedValues.Keys)
                {
                    returnValues.Add(SimpleMemcachedKeyGroup.RemoveGroupFromCachedKey(groupName, key), memcachedValues[key]);
                }

                //var currentSimpleCachedKeyGroups = SimpleMemcachedKeyGroup.Current;

                //if (!currentSimpleCachedKeyGroups.ContaintsGroup(groupName)) return null;

                //var keysList =
                //    cachedKeys.Select(cachedKey => currentSimpleCachedKeyGroups.GetMemcachedKey(groupName, cachedKey)).
                //        Where(existsKey => !string.IsNullOrEmpty(existsKey)).ToList();

                //if (keysList.Count == 0) return null;

                //var memcachedValues = _memcachedClient.Get(keysList);

                //foreach (var key in memcachedValues.Keys)
                //{
                //    returnValues.Add(currentSimpleCachedKeyGroups.RemoveGroupFromCachedKey(groupName, key), memcachedValues[key]);
                //}
            }
            else
            {
                IList<string> keysList = cachedKeys.Select(cachedKey => groupName + cachedKey).ToList();
                var memcachedValues = _memcachedClient.Get(keysList);
                foreach (var key in memcachedValues.Keys)
                {
                    returnValues.Add(key.Substring(groupName.Length), memcachedValues[key]);
                }
            }

            return returnValues;
        }

        public void Remove(string groupName, string cachedKey)
        {
            if (!EnableCache) return;

            if (UseCachedKeyManager && !string.IsNullOrEmpty(groupName))
            {
                //var currentCachedKeyGroups = MemcachedKeyGroups.Current;
                //if (!currentCachedKeyGroups.ContaintsKey(groupName, cachedKey)) return;
                //var cacheKeys = currentCachedKeyGroups[groupName];
                //_memcachedClient.Remove(cacheKeys.GetPublishedKey(cachedKey));
                //cacheKeys.Remove(cachedKey);

                //var currentSimpleCachedKeyGroups = SimpleMemcachedKeyGroup.Current;
                //if (!currentSimpleCachedKeyGroups.ContaintsKey(groupName, cachedKey)) return;
                //_memcachedClient.Remove(currentSimpleCachedKeyGroups.GetMemcachedKey(groupName, cachedKey));
                //currentSimpleCachedKeyGroups.RemoveKey(groupName, cachedKey);

                _memcachedClient.Remove(SimpleMemcachedKeyGroup.GetPublishKey(groupName, cachedKey));
                var currentSimpleCachedKeyGroups = SimpleMemcachedKeyGroup.Current;
                currentSimpleCachedKeyGroups.RemoveKey(groupName, cachedKey);
            }
            else
            {
                _memcachedClient.Remove(groupName + cachedKey);
            }
        }
        //public void RemoveAll(string groupName)
        //{
        //    if (!EnableCache || !UseCachedKeyManager || string.IsNullOrEmpty(groupName)) return;

        //    //var currentCachedKeyGroups = MemcachedKeyGroups.Current;

        //    //// Group có tồn tại
        //    //if (!currentCachedKeyGroups.ContaintsGroup(groupName)) return;

        //    //var cacheKeys = currentCachedKeyGroups[groupName];
        //    //// Xóa toàn bộ cache
        //    //foreach (var key in cacheKeys.GetAllKeys())
        //    //{
        //    //    _memcachedClient.Remove(cacheKeys.GetPublishedKey(key));
        //    //}
        //    //currentCachedKeyGroups.RemoveGroup(groupName);

        //    //var currentSimpleCachedKeyGroups = SimpleMemcachedKeyGroup.Current;

        //    //// Group có tồn tại
        //    //if (!currentSimpleCachedKeyGroups.ContaintsGroup(groupName)) return;

        //    //var cacheKeys = currentSimpleCachedKeyGroups[groupName];
        //    //// Xóa toàn bộ cache
        //    //foreach (var key in cacheKeys)
        //    //{
        //    //    _memcachedClient.Remove(currentSimpleCachedKeyGroups.GetMemcachedKey(groupName, key));
        //    //}
        //    //currentSimpleCachedKeyGroups.RemoveGroup(groupName);

        //    var currentSimpleCachedKeyGroups = SimpleMemcachedKeyGroup.Current;
        //    if (currentSimpleCachedKeyGroups.ContaintsGroup(groupName))
        //    {
        //        var cacheKeys = currentSimpleCachedKeyGroups[groupName];
        //        foreach (var cacheKey in cacheKeys)
        //        {
        //            _memcachedClient.Remove(SimpleMemcachedKeyGroup.GetPublishKey(groupName, cacheKey));
        //        }
        //    }
        //    currentSimpleCachedKeyGroups.RemoveGroup(groupName);
        //}
        public void RemoveAllPort()
        {
            if (!EnableCache) return;

            _memcachedClient.FlushAll();
        }
    }
}
